#include <iostream>
#include <exception>
#include <functional>
#include <algorithm>
#include <vector>
#include <memory>
#include <set>
#include <stdint.h>
#include <random>
#include <exception>
#include <queue>


#include "GameState.h"
#include "IOWorker.h"
#include "Common.h"
#include "Ant.h"
#include "EmptyCell.h"
#include "Water.h"
#include "Food.h"
#include "AntHill.h"
#include "Strategy.h"
#include "Algorithm.h"
#include "Move.h"

/*
        cerr для вывода отлаочной информации от бота
        cout для передачи команд серверу муравьёв
        cin  для приём данных от сервера

 */

using namespace std;

int main(int argc, char *argv[]) {
    /*GameState tmpState(10, 10);
    Ant a1(1,1,true);
    Water w2(1,0);
    Water w3(2,1);
    Water w4(1,2);
    Water w6(0,2);
   
    tmpState.setXY(a1);
    tmpState.setXY(w2);
    tmpState.setXY(w3);
    tmpState.setXY(w4);
    tmpState.setXY(w6);
    
    tmpState.setXY(3, 3, FOOD);
    
    
    tmpState.printState();
    
    char move;
    bool res = Algorithm::findASPath(tmpState, a1, 3,3, move);
    if (res)
    {
        cerr << "Путь найден" << endl;
        cerr << "Муравью надо идти на " << move << endl;
    }
    else
    {
        cerr << "Путь не найден!" << endl;
    }
    
    return 0;
    Ant aa(10, 20, true);
    Ant aa2(10, 22, true);
    Ant aa3(9, 21, true);
    Coord dest1 = {10, 21};
    Coord dest2 = {10, 23};
    Coord dest3 = {10, 21};

    Move m1(aa, dest1, 'e');
    Move m2(aa2, dest2, 'e');
    Move m3(aa3, dest3, 's');
    
    deque<Move> dq = {m1, m2, m3};
    for (auto it : dq)
    {
        cerr << "Cell is: {" << it.getAnt().row() << ',' << it.getAnt().column() << "}, dest is ";
        cerr << '{' << it.getDest().row << ',' << it.getDest().column << '}' << endl;
    }
    cerr << "После обработки:" << endl;
    sort(dq.begin(), dq.end());
    // теперь величины с одинаковым dest Рядом
    auto it = dq.begin();
    
    while (it != dq.end())
    {
        vector <Move> mms;
        auto upper = upper_bound(it, dq.end(), *it);
        auto lower = lower_bound(it, dq.end(), *it);
        for (auto tt = lower; tt != upper; tt++)
        {
            mms.push_back(*tt);
        }
        
        Move & m = mms.back();
        cerr << "o " << m.getAnt().row() << ' ' << m.getAnt().column() << ' ' << m.getMove() << endl;
        
        dq.erase(it, upper - 1);
        it = upper;
    }
    
    return 0;*/
    cerr << "All right!" << endl;
    GameConf conf;

    IOWorker::loadConfTurn(conf);
    IOWorker::printConf(conf);
    IOWorker::endTurn();

    GameState state(conf.rows, conf.cols);

    while (!conf.isGameOver) {
        try
        {
            // ввод информации
            IOWorker::startTurn(state, conf);
            
            // обработка информации
            Strategy::setAntsState(state, conf);

            state.printState();
            Strategy::collisionDetect(state);

            // вывод информации
            IOWorker::outputTurn(state);
            IOWorker::endTurn(state);
        }
        catch (const exception & ex)
        {
            // TODO обработка ошибок. не дадим сбить нас с ног!
            cerr << ex.what() << endl;
            return 1;
        }
    }

    return 0;
}
